package binance

import (
	"context"
	"encoding/json"

	"gitee.com/hacker61/go-binance/v2/common"
)

// ListSwapPoolsService list all bswap pools
type ListSwapPoolsService struct {
	c *Client
}

func (s *ListSwapPoolsService) Do(ctx context.Context, opts ...RequestOption) (res []*SwapPoolMetaData, err error) {
	r := &request{
		method:   "GET",
		endpoint: "/sapi/v1/bswap/pools",
		secType:  secTypeAPIKey,
	}
	data, err := s.c.callAPI(ctx, r, opts...)
	data = common.ToJSONList(data)
	if err != nil {
		return []*SwapPoolMetaData{}, err
	}
	res = make([]*SwapPoolMetaData, 0)
	err = json.Unmarshal(data, &res)
	if err != nil {
		return []*SwapPoolMetaData{}, err
	}
	return res, nil
}

type SwapPoolMetaData struct {
	PoolId   int64    `json:"poolId"`
	PoolName string   `json:"poolName"`
	Assets   []string `json:"assets"`
}

// RequestSwapQuoteService get swap quote
type RequestSwapQuoteService struct {
	c          *Client
	quoteAsset string
	baseAsset  string
	quoteQty   float64
}

func (s *RequestSwapQuoteService) QuoteAsset(quoteAsset string) *RequestSwapQuoteService {
	s.quoteAsset = quoteAsset
	return s
}

func (s *RequestSwapQuoteService) BaseAsset(baseAsset string) *RequestSwapQuoteService {
	s.baseAsset = baseAsset
	return s
}

func (s *RequestSwapQuoteService) QuoteQty(quoteQty float64) *RequestSwapQuoteService {
	s.quoteQty = quoteQty
	return s
}

func (s *RequestSwapQuoteService) Do(ctx context.Context, opts ...RequestOption) (res *SwapQuoteMetaData, err error) {
	r := &request{
		method:   "GET",
		endpoint: "/sapi/v1/bswap/quote",
		secType:  secTypeSigned,
	}
	r.setParam("quoteAsset", s.quoteAsset)
	r.setParam("baseAsset", s.baseAsset)
	r.setParam("quoteQty", s.quoteQty)
	data, err := s.c.callAPI(ctx, r, opts...)
	if err != nil {
		return nil, err
	}
	res = new(SwapQuoteMetaData)
	err = json.Unmarshal(data, res)
	if err != nil {
		return nil, err
	}
	return res, nil
}

type SwapQuoteMetaData struct {
	QuoteAsset string `json:"quoteAsset"`
	BaseAsset  string `json:"baseAsset"`
	QuoteQty   string `json:"quoteQty"`
	BaseQty    string `json:"baseQty"`
	Price      string `json:"price"`
	Slippage   string `json:"slippage"`
	Fee        string `json:"fee"`
}

// GetPoolConfigureService get pool confiture
type GetPoolConfigureService struct {
	c      *Client
	poolId *int64
}

func (s *GetPoolConfigureService) PoolId(poolId int64) *GetPoolConfigureService {
	s.poolId = new(int64)
	*s.poolId = poolId
	return s
}

func (s *GetPoolConfigureService) Do(ctx context.Context, opts ...RequestOption) (res []*PoolConfiture, err error) {
	r := &request{
		method:   "GET",
		endpoint: "/sapi/v1/bswap/poolConfigure",
		secType:  secTypeSigned,
	}
	if s.poolId != nil {
		r.setParam("poolId", *s.poolId)
	}
	data, err := s.c.callAPI(ctx, r, opts...)
	if err != nil {
		return nil, err
	}
	res = make([]*PoolConfiture, 0)
	err = json.Unmarshal(data, &res)
	if err != nil {
		return []*PoolConfiture{}, err
	}

	return res, nil
}

type PoolConfiture struct {
	PoolId     int64                     `json:"poolId"`
	PoolName   string                    `json:"poolName"`
	UpdateTime int64                     `json:"updateTime"`
	Liqui      Liquidity                 `json:"liquidity"`
	AssetConf  map[string]AssetConfigure `json:"assetConfigure"`
}

type Liquidity struct {
	ConstantA         int64  `json:"constantA"`
	MinRedeemShare    string `json:"minRedeemShare"`
	SlippageTolerance string `json:"slippageTolerance"`
}

type AssetConfigure struct {
	MinAdd  string `json:"minAdd"`
	MaxAdd  string `json:"maxAdd"`
	MinSwap string `json:"minSwap"`
	MaxSwap string `json:"maxSwap"`
}
